package com.snjx.micro.oauth.gateway.config.netty;

import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
import org.springframework.stereotype.Component;
import reactor.netty.http.server.HttpServer;

/**
 * @author by suonanjiexi
 * @version 1.0
 * @apiNote TODO
 * @date 2020/8/5 2:30 下午
 */
@Component
public class EventLoopNettyCustomizer implements NettyServerCustomizer {
    private  HttpServerConfig httpServerConfig;
    @Override
    public HttpServer apply(HttpServer httpServer) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(httpServerConfig.getGroup().getBossGroupThreads());
        EventLoopGroup workGroup = new NioEventLoopGroup(httpServerConfig.getGroup().getWorkGroupThreads());
        //.option用于设置bossGroup相关参数
        //.childOption用于设置workerGroup相关参数
         httpServer.tcpConfiguration(tcpServer -> tcpServer
                .bootstrap(serverBootstrap -> serverBootstrap
                        .group(bossGroup, workGroup)
                        .channel(NioServerSocketChannel.class)
                        //添加心跳
                        .childHandler(new IdleStateHandler(httpServerConfig.getIdleTime().getReaderIdleTimeSeconds(),httpServerConfig.getIdleTime().getWriterIdleTimeSeconds(),httpServerConfig.getIdleTime().getAllIdleTimeSeconds()))
                        .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                        .handler(new LoggingHandler(LogLevel.INFO))
                        .childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(64, 2048, 65536))
                )
                //地址端口复用
                .selectorOption(ChannelOption.SO_REUSEADDR,true)
                //
                .option(ChannelOption.SO_BACKLOG,httpServerConfig.getChannel().getSoBacklog())
                //利用TCP的SO_KEEPALIVE属性
                .option(ChannelOption.SO_KEEPALIVE,true)
                //禁用nagle算法，不等待，立即发送
                .option(ChannelOption.TCP_NODELAY, true)
                //收发缓冲区buffer大小
                .option(ChannelOption.SO_RCVBUF,httpServerConfig.getChannel().getSoRcvbuf())
                .option(ChannelOption.SO_SNDBUF,httpServerConfig.getChannel().getSoSndbuf())
                // zeor copy  在IO操作中，分配直接内存而不是JVM的堆空间，避免在发送数据时，从JVM到直接内存的拷贝过程
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                //连接超时
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,httpServerConfig.getChannel().getConnectTimeOutMillis())
               )
                //使用http2协议
                //.protocol(HttpProtocol.H2)
                ;
        // 绑定端口，开始接收进来的连接
        //ChannelFuture future = b.bind(port).sync(); // (7)
        return httpServer;
    }
}

